/**
  *****************************************************************************
  * @file 
  * @brief 
  * @author  Moon
  * @version
  * @date    2022/09/02
  *****************************************************************************
  */
/* Includes -----------------------------------------------------------------*/
#include "dev_fm24clxx.h"

/* Private defines ----------------------------------------------------------*/
#define CHIP_ADDR	0xA0
/* Private Struct -----------------------------------------------------------*/

/* Private enum -------------------------------------------------------------*/

/* Private Variable ---------------------------------------------------------*/
//Pointer

//Array

//Const

/* Private function prototypes ----------------------------------------------*/

/*****************************************************************************
* @brief  开启写
* ex:
* @par
* None
* @retval
*****************************************************************************/
static void Fm24_Write_Enable(dev_fm24_t *this)
{
	if (this->PIN_WP == NULL)
		return;

	this->private.gpio_wp.Write(&this->private.gpio_wp, 0);
}

/*****************************************************************************
* @brief  关闭写
* ex:
* @par
* None
* @retval
*****************************************************************************/
static void Fm24_Write_Disable(dev_fm24_t *this)
{
	if (this->PIN_WP == NULL)
		return;

	this->private.gpio_wp.Write(&this->private.gpio_wp, 1);
}

/*****************************************************************************
* @brief  从FM24铁电读取数据
* ex:
* @par
* None
* @retval 返回实际读取的数据长度
*****************************************************************************/
static uint16_t Fm24_Read(dev_fm24_t *this, uint16_t addr, uint8_t *buf, uint16_t len)
{
	if (this == NULL || buf == NULL)
		return 0;

	if ((addr + len) >= this->chip_size)
		return 0;

	if (this->private.i2c.Read(&this->private.i2c, CHIP_ADDR, addr, buf, len) != 0)
		return 0;
	return len;
}

/*****************************************************************************
* @brief  向FM24铁电写入数据
* ex:
* @par
* None
* @retval 返回实际写入的数据长度
*****************************************************************************/
static uint16_t Fm24_Write(dev_fm24_t *this, uint16_t addr, uint8_t *buf, uint16_t len)
{
	uint8_t reg = len;

	if (this == NULL || buf == NULL || len == 0)
		return 0;

	if ((addr + len) >= this->chip_size)
		return 0;

	Fm24_Write_Enable(this);

	if (this->private.i2c.Write(&this->private.i2c, CHIP_ADDR, addr, buf, len) != 0)
		reg = 0;

	Fm24_Write_Disable(this);
	return reg;
}

/*****************************************************************************
* @brief  向FM24铁电写入数据
* ex:
* @par
* None
* @retval 返回实际写入的数据长度
*****************************************************************************/
static int Fm24_Check(dev_fm24_t *this)
{
	uint8_t write[] = "abcdefg";
	uint8_t save[8];
	uint8_t read[8];

	// 原始值保留
	this->Read(this, 0x0000, (uint8_t *)save, 8);
	// 写入已知
	this->Write(this, 0x0000, (uint8_t *)write, 8);
	// 读取
	this->Read(this, 0x0000, (uint8_t *)read, 8);
	// 写入原始值
	this->Write(this, 0x0000, (uint8_t *)save, 8);
	// 对比
	if (strcmp((const char *)write, (const char *)read) != 0)
	{
		return -1;
	}

	return 0;
}

/*****************************************************************************
* @brief  功能说明：FRAM端口和读写控制初始化
* ex:
* @par    输入参数：dev_fm24_t *this - FRAM 端口和读写控制信息
*         输出参数：dev_fm24_t *this - FRAM 端口和读写控制信息
* None
* @retval 返回值：初始化完成返回0，否则返回-1
*****************************************************************************/
int Dev_Fm24_Init(dev_fm24_t *this)
{
	// I2C对象初始化
	this->private.i2c.PIN_SDA = this->PIN_SDA;
	this->private.i2c.PIN_SCL = this->PIN_SCL;
	this->private.i2c.SPEED = I2C_SPEED_SLOW;
	this->private.i2c.WIDTH = I2C_WIDTH_HALFWORLD;
	this->private.i2c.ACK_TIMEOUT = I2C_TIMEOUT_STOP;
	this->private.i2c.ACK_WAIT_US = 100;
	if (Drv_I2c_Init(&this->private.i2c) < 0)
	{
		return -1;
	}

	// Write Protect
	if (this->PIN_WP != NULL)
	{
		this->private.gpio_wp.PIN = this->PIN_WP;
		this->private.gpio_wp.MODE = OUTPUT_DOWN;
		this->private.gpio_wp.INIT_LEVEL = LOW_LEVEL; // low level inhibit write to Status Register when WPEN is 1
		if (Drv_Gpio_Init(&this->private.gpio_wp) < 0)
		{
			return -1;
		}
	}

	// 公共方法赋值
	this->Write = Fm24_Write;
	this->Read = Fm24_Read;
	this->Check = Fm24_Check;

	// 寄存器设置
	if (Fm24_Check(this) < 0)
	{
		return -1;
	}
	return 0;
}
